package com.le.tester.imooc.oldimmortal.coding.buffer;

import org.junit.Test;

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;

/**
 * createTime：2025-05-16 14:34
 * description：统计词频
 */
public class WordCount {

    //    更利于多个子任务不平衡执行的时候
    public ForkJoinPool forkJoinPool = new ForkJoinPool();
    public ExecutorService es = Executors.newCachedThreadPool();


    @Test
    public void compareWithSingle() throws IOException {

        String filePath = "word.txt";
        BufferedInputStream bIn = new BufferedInputStream(new FileInputStream(filePath));
//        每次读取的len
        int len;
        HashMap<String, Integer> map = new HashMap<>();
        byte[] byteSize = new byte[4 * 1024];
        long startTime = System.currentTimeMillis();
        while ((len = bIn.read(byteSize)) != -1) {
            byte[] bytes = Arrays.copyOfRange(byteSize, 0, len);
            String str = new String(bytes);
            HashMap<String, Integer> hashMap = countByString(str);

            for (Map.Entry<String, Integer> mapItem : hashMap.entrySet()) {
                String key = mapItem.getKey();
                incKey(key, mapItem.getValue(), map);
            }
        }
        System.out.println("time:" + (System.currentTimeMillis() - startTime) + "ms");
        System.out.println(map.get("ababb"));
        System.out.println(map.size());
    }

    private HashMap<String, Integer> countByString(String str) {
        HashMap<String, Integer> result = new HashMap<>();
        StringTokenizer tokenizer = new StringTokenizer(str);
        while (tokenizer.hasMoreTokens()) {
            String word = tokenizer.nextToken();
            incKey(word, 1, result);
        }
        return result;
    }

    private void incKey(String word, int count, HashMap<String, Integer> result) {
        if (result.containsKey(word)) {
            Integer currentCount = result.get(word);
            result.put(word, currentCount + count);
        } else {
            result.put(word, count);
        }

    }


    class CountTask implements Callable<HashMap<String, Integer>> {

        public final long start;

        public final long end;

        public final String fileName;

        public CountTask(long start, long end, String fileName) {
            this.start = start;
            this.end = end;
            this.fileName = fileName;
        }

        @Override
        public HashMap<String, Integer> call() throws Exception {
            //    任意的读写文件
            FileChannel channel = new RandomAccessFile(this.fileName, "rw").getChannel();
//        文件映射到内存
            MappedByteBuffer mBuf = channel.map(FileChannel.MapMode.READ_ONLY, this.start, this.end - this.start);
//        给到string
            String str = StandardCharsets.US_ASCII.decode(mBuf).toString();
            return countByString(str);
        }


    }

    public void run(String fileName, long chunkSize) throws ExecutionException, InterruptedException {
        File file = new File(fileName);
        long length = file.length();

        long position = 0;
        long startTime = System.currentTimeMillis();
        ArrayList<Future<HashMap<String, Integer>>> taskList = new ArrayList<>();

        while (position < length) {
            long next = Math.min(position + chunkSize, length);

//            分片的任务
            CountTask countTask = new CountTask(position, next, fileName);
            position = next;
            ForkJoinTask<HashMap<String, Integer>> task = forkJoinPool.submit(countTask);
            taskList.add(task);
        }
        System.out.format("split to %d tasks\n", taskList.size());

        HashMap<String, Integer> totalMap = new HashMap<>();

        for (Future<HashMap<String, Integer>> item : taskList) {
            HashMap<String, Integer> map = item.get();
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                incKey(entry.getKey(), entry.getValue(), totalMap);
            }

        }
        System.out.println("time:" + (System.currentTimeMillis() - startTime) + "ms");
        System.out.println("total:" + totalMap.size());

        System.out.println(totalMap.get("ababb"));

    }

    @Test
    public void count() throws ExecutionException, InterruptedException {
        String filePath = "word.txt";
        WordCount wordCount = new WordCount();
        System.out.println("processors:" + Runtime.getRuntime().availableProcessors());
        wordCount.run(filePath, 1024 * 1024 * 10);
    }
}

